package easylog

import (
	"context"
	"fmt"
	"io"
	"log/slog"
	"runtime"
	"time"
)

func NewDefaultLogger(level slog.Level) *EasyLogger {
	return NewEasyLogger(level, "", nil, 3)
}

func NewEasyLogger(level slog.Level, filePath string, remote io.Writer, skipCallers int) *EasyLogger {
	var lvl slog.LevelVar
	lvl.Set(level)

	slogger := slog.New(NewEasyHandler(filePath, remote, &lvl))

	return &EasyLogger{
		slogger:     slogger,
		lvl:         &lvl,
		filePath:    filePath,
		remote:      remote,
		skipCallers: skipCallers,
	}
}

type EasyLogger struct {
	slogger     *slog.Logger
	lvl         *slog.LevelVar
	filePath    string
	remote      io.Writer
	skipCallers int
}

// SetLogLevel 动态调整日志级别
func (my *EasyLogger) SetLogLevel(level slog.Level) {
	my.lvl.Set(level)
}

func (my *EasyLogger) Debug(format string, args ...any) {
	my.log(context.Background(), slog.LevelDebug, fmt.Sprintf(format, args...))
}

func (my *EasyLogger) Info(format string, args ...any) {
	my.log(context.Background(), slog.LevelInfo, fmt.Sprintf(format, args...))
}

func (my *EasyLogger) Warn(format string, args ...any) {
	my.log(context.Background(), slog.LevelWarn, fmt.Sprintf(format, args...))
}

func (my *EasyLogger) Error(format string, args ...any) {
	my.log(context.Background(), slog.LevelError, fmt.Sprintf(format, args...))
}

func (my *EasyLogger) Close() {
	my.SetLogLevel(slog.LevelError + 1)
}

func (my *EasyLogger) Println(format string, v ...any) {
	if eh, ok := my.slogger.Handler().(*EasyHandler); ok {
		r := Record{
			Record: slog.Record{
				Time: time.Now(),
			},
		}
		eh.println(fmt.Sprintf(format, v...), r)
	}
}

// log is the low-level logging method for methods that take ...any.
// It must always be called directly by an exported logging method
// or function, because it uses a fixed call depth to obtain the pc.
func (my *EasyLogger) log(ctx context.Context, level slog.Level, msg string, args ...any) {
	if !my.slogger.Enabled(ctx, level) {
		return
	}
	var pc uintptr
	var pcs [1]uintptr
	// skip [runtime.Callers, this function, this function's caller]
	// NOTE: 这里注意，*slog.Logger.log 源码中 skip 为 3，该方法每被多调用一层， skip 需要 +1，
	skipCallers := 3
	if my.skipCallers > 3 {
		skipCallers = my.skipCallers
	}
	runtime.Callers(skipCallers, pcs[:])
	pc = pcs[0]
	r := slog.NewRecord(time.Now(), level, msg, pc)
	r.Add(args...)
	if ctx == nil {
		ctx = context.Background()
	}
	_ = my.slogger.Handler().Handle(ctx, r)
}
